package com.smart.quartz.task;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smart.common.constant.GlobalConstants;
import com.smart.common.core.domain.DeviceInfo;
import com.smart.common.core.domain.entity.SysDept;
import com.smart.common.utils.DateUtils;
import com.smart.common.utils.StringUtils;
import com.smart.common.utils.ffmpeg.FfmpegUtils;
import com.smart.common.utils.file.FileUtils;
import com.smart.common.utils.task.TaskUtils;
import com.smart.system.domain.*;
import com.smart.system.service.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.text.ParseException;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component("smartTask")
public class SmartTask {

    @Autowired
    private TaskUtils taskUtils;

    @Autowired
    private IBucketCapacityRecordService bucketCapacityRecordService;

    @Autowired
    private IBucketTotalService bucketTotalService;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private IEmployeeService employeeService;

    @Autowired
    private IWorkingScheduleService workingScheduleService;

    @Autowired
    private IAttendanceRecordService attendanceRecordService;

    @Autowired
    private IWatchesService watchersService;

    @Autowired
    private IEmployeeTrajectoryService employeeTrajectoryService;

    @Autowired
    private IAreaService areaService;

    @Autowired
    private IAreaEmployeeService areaEmployeeService;

    @Autowired
    private ICarService carService;

    @Autowired
    private IMobileUnitService mobileUnitService;

    @Autowired
    private ICarTrajectoryService cartrajectoryService;

    @Autowired
    private IFfmpegService ffmpegService;

    @Autowired
    private IBucketService bucketService;

    @Autowired
    private FfmpegUtils ffmpegUtils;

    @Autowired
    private IConfigService configService;

    @Autowired
    private IAlarmService alarmService;

    @Autowired
    private IAreaCarService areaCarService;

    private static final Logger logger = LoggerFactory.getLogger(SmartTask.class);
    /**
     * 告警信息定时器
     */
    @Transactional(rollbackFor = Exception.class)
    public synchronized void giveAnAlarmTask() {
        if (taskUtils.isTaskExist("giveAnAlarmTask")) {
            logger.info("告警信息定时任务正在执行中，请勿重复执行");
            return;
        }
        logger.info("开始执行告警信息定时任务");
        taskUtils.addTask("giveAnAlarmTask",30L, TimeUnit.SECONDS);
        // 获取所有垃圾桶平台类型的桶
        List<Bucket> buckets = bucketService.list(
                Wrappers.lambdaQuery(Bucket.class)
                        .eq(Bucket::getType, GlobalConstants.BUCKET_TYPE_BUCKET_PLATFORM)
        );

        if (buckets.isEmpty()) {
            return;
        }

        List<Alarm> alarms = new LinkedList<>();
        // 获取区域列表用于确定桶所在区域
        List<Area> areas = areaService.list();

        // 定义容量范围常量，提高可读性
        final int MIN_CAPACITY_VALUE = 4;
        final int CAPACITY_RANGE = 15; // 19-4=15

        for (Bucket bucket : buckets) {
            // 拿到最后十五条数据，取其中最大值
            List<BucketCapacityRecord> records = bucketCapacityRecordService.list(
                    Wrappers.lambdaQuery(BucketCapacityRecord.class)
                            .eq(BucketCapacityRecord::getBucketId, bucket.getId())
                            .orderByDesc(BucketCapacityRecord::getCreateTime)
                            .last("limit 15")
            );

            // 获取最新的容量数值
            int maxValue = records.stream()
                    .map(BucketCapacityRecord::getNumber)
                    .max(Integer::compareTo)
                    .orElse(0);

            // 将 maxValue 转换为百分比 (4-19 对应 0%-100%)
            int percentage = Math.max(0, Math.min(100,
                    (int) Math.round(((double) (maxValue - MIN_CAPACITY_VALUE) * 100) / CAPACITY_RANGE)));

            // 判断是否超过阈值
//            boolean isOverThreshold = (100-percentage) > bucket.getThresholdValue();
            bucket.setThreshold(100-percentage);
            // 查找桶所在的区域ID
//            Integer areaId = findBucketAreaId(bucket, areas);

//            if (isOverThreshold) {
//                // 检查是否已存在相同类型的未读告警
//                Alarm existingAlarm = alarmService.getOne(
//                        Wrappers.lambdaQuery(Alarm.class)
//                                .eq(Alarm::getType, GlobalConstants.TRASH_CAN)
//                                .eq(Alarm::getToId, bucket.getId())
//                                .eq(Alarm::getStatus, GlobalConstants.YES_CHECKED)
//                                .eq(Alarm::getMessage, Alarm.Message.REACH_THRESHOLD.getCode())
//                                .orderByDesc(Alarm::getCreateTime)
//                                .last("limit 1")
//                );
//
//                // 如果已存在相同未读告警，则跳过
//                if (existingAlarm != null) {
//                    bucket.setAlarm(Alarm.Message.toMessage(existingAlarm.getMessage()));
//                }else{
//                    // 创建新的告警
//                    Alarm alarm = Alarm.builder()
//                            .type(GlobalConstants.TRASH_CAN)
//                            .toId(bucket.getId())
//                            .message(Alarm.Message.REACH_THRESHOLD.getCode())
//                            .areaId(areaId)
//                            .createTime(new Date())
//                            .build();
//
//                    alarms.add(alarm);
//                    bucket.setAlarm(Alarm.Message.toMessage(alarm.getMessage()));
//                }
//            } else {
//                // 将此类型所有达到阈值的未读告警改为已读
//                alarmService.update(
//                        Wrappers.lambdaUpdate(Alarm.class)
//                                .eq(Alarm::getType, GlobalConstants.TRASH_CAN)
//                                .eq(Alarm::getToId, bucket.getId())
//                                .eq(Alarm::getMessage, Alarm.Message.REACH_THRESHOLD.getCode())
//                                .eq(Alarm::getStatus, GlobalConstants.YES_CHECKED)
//                                .set(Alarm::getStatus, GlobalConstants.NO_CHECKED)
//                );
//            }
        }

        // 批量更新桶的状态和保存告警信息
        try {
            bucketService.updateBatchById(buckets);
//            if (!alarms.isEmpty()) {
//                alarmService.saveBatch(alarms);
//            }
        } catch (Exception e) {
            // 记录异常但不中断整个任务
            e.printStackTrace();
            throw e;
        }
        logger.info("结束执行告警信息定时任务");
    }

    /**
     * 查找桶所在的区域ID
     * @param bucket 桶对象
     * @param areas 区域列表
     * @return 区域ID，如果未找到返回null
     */
    private Integer findBucketAreaId(Bucket bucket, List<Area> areas) {
        if (bucket.getAreaLocation() == null) {
            return null;
        }

        return areas.stream()
                .filter(area -> area.getAreaLocations() != null)
                .filter(area -> AreaLocation.isPointInPolygon(bucket.getAreaLocation(), area.getAreaLocations()))
                .findFirst()
                .map(Area::getId)
                .orElse(null);
    }

    /**
     * 车载设备定位自动获取
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateCarTrajectoryTask(){
        //获取所有车辆
        List<Car> cars = carService.list();
        //获取在线的设备
        List<String> deviceOnline = mobileUnitService.getDeviceOnline(cars.stream().map(Car::getCarNumber).collect(Collectors.toList()));
        //清除掉不对的数据
        List<String> numbers = deviceOnline.stream()
                .filter(str -> str!= null && !str.equals(""))
                .collect(Collectors.toList());
        List<DeviceInfo> carInfoDetails = mobileUnitService.getCarInfoDetails(numbers);
        List<CarTrajectory> carTrajectories = new LinkedList<>();
        for (DeviceInfo carInfoDetail : carInfoDetails) {
            //记录车辆定位
            CarTrajectory carTrajectory = new CarTrajectory();
            for (Car car : cars) {
                if(car.getCarNumber().equals(carInfoDetail.getId())){
//                    carTrajectory.setAreaLocation(new AreaLocation(carInfoDetail.getId(), carInfoDetail.getMlng(), carInfoDetail.getMlat()));

                    //获取这辆车最近一次的经纬度数据,波动较小,则跳过
                    CarTrajectory one = cartrajectoryService.getOne(Wrappers.lambdaQuery(CarTrajectory.class).eq(CarTrajectory::getCarId, car.getId()).orderByDesc(CarTrajectory::getCreateTime).last("limit 1"));
                    AreaLocation areaLocation = null;
                    if (one!=null){
                        areaLocation = AreaLocation.filterGpsPoint(one.getAreaLocation(), new AreaLocation(carInfoDetail.getId(), carInfoDetail.getMlng(), carInfoDetail.getMlat(),null), GlobalConstants.CAR_LOCATION_THRESHOLD_VALUE);
                    }else{
                        areaLocation = new AreaLocation(carInfoDetail.getId(), carInfoDetail.getMlng(), carInfoDetail.getMlat(),null);
                    }
                    //放入通过算法计算后的结果
                    carTrajectory.setAreaLocation(areaLocation);

                    carTrajectory.setDeptId(Integer.parseInt(car.getDeptId()));
                    carTrajectory.setCarId(car.getId());
                    carTrajectory.setCreateTime(new Date());
                    carTrajectory.setCreateBy(GlobalConstants.JOB);
                    //不知道是不是这个油量
                    carTrajectory.setOilLevel(carInfoDetail.getViceYl());
                    //当前时速
                    carTrajectory.setSpeed(carInfoDetail.getSp());
                    //判断是否超速
                    Config config =  configService.getOne(Wrappers.lambdaQuery(Config.class).last("limit 1"));

                    //判断车辆是否在区域内
                    //获取该车辆所属区域
                    AreaCar areaCar = areaCarService.getOne(Wrappers.lambdaQuery(AreaCar.class).eq(AreaCar::getCarId, car.getId()).last("limit 1"));
                    if(areaCar!=null){
                        Area area = areaService.getById(areaCar.getAreaId());
                        if(area!=null){
                            //判断是否在区域内
                            if(!AreaLocation.isPointInPolygon(areaLocation, area.getAreaLocations())){
                                //插入告警信息
                                //判断是否存在同类型,并且未读的告警
                                Alarm alarm = alarmService.getOne(Wrappers.lambdaQuery(Alarm.class)
                                        .eq(Alarm::getType, Alarm.CAR)
                                        .eq(Alarm::getToId, car.getId())
                                        .eq(Alarm::getStatus, GlobalConstants.YES_CHECKED)
                                        .last("limit 1"));
                                if(alarm==null){
                                    alarmService.save(Alarm.getByMessage(Alarm.Message.OUT_OF_AREA, Alarm.CAR, car.getId(),areaCar.getAreaId()));
                                }

                            }
                            //判断限速
                            if(config!=null&&StringUtils.isNotBlank(config.getSpeedLimit())){
                                if (carInfoDetail.getSp()>Double.parseDouble(config.getSpeedLimit())) {
                                    //查询是否已经有同类型告警信息,并且是未读状态,如果是则不添加
                                    Alarm alarm = alarmService.getOne(Wrappers.lambdaQuery(Alarm.class)
                                            .eq(Alarm::getType, Alarm.CAR)
                                            .eq(Alarm::getToId, car.getId())
                                            .eq(Alarm::getStatus, GlobalConstants.YES_CHECKED)
                                            .last("limit 1"));
                                    if (alarm!=null){
                                        continue;
                                    }
                                    //插入告警信息
                                    alarmService.save(Alarm.getByMessage(Alarm.Message.OVER_SPEED, Alarm.CAR, car.getId(),areaCar.getAreaId()));
                                }
                            }
                        }
                    }
                    carTrajectories.add(carTrajectory);
                    break;
                }
            }
        }
        cartrajectoryService.saveBatch(carTrajectories);
    }

    /**
     * 用户手表在线心跳,车辆在线心跳
     */
    @Transactional(rollbackFor = Exception.class)
    public void watchHeartBeatTask() {
        //获取所有用户
        List<Employee> list = employeeService.list(Wrappers.lambdaQuery(Employee.class).isNotNull(Employee::getImei));

        List<Employee> updateEmployees = new LinkedList<Employee>();
        for (Employee employee : list) {
            if (employee.getImei() == null) {
                continue;
            }
            Integer deviceOnline = watchersService.getDeviceOnline(employee.getImei());
            employee.setOnline(deviceOnline);
            //手表在线则设置上传时间,可以不要
//            if(deviceOnline==0){
//
//            }
            updateEmployees.add(employee);
        }
        for (Employee updateEmployee : updateEmployees) {
            employeeService.updateEmployee(updateEmployee);
        }

        //获取所有车辆
        List<Car> cars = carService.list();
        List<String> deviceOnline = mobileUnitService.getDeviceOnline(cars.stream().map(Car::getCarNumber).collect(Collectors.toList()));
        if(deviceOnline!=null&&deviceOnline.size()>0){
            carService.update(Wrappers.lambdaUpdate(Car.class).in(Car::getCarNumber, deviceOnline).set(Car::getOnline, GlobalConstants.SUCCESS));
        }
        for (Car car : cars) {
            if(deviceOnline.contains(car.getCarNumber())){
                //在线修改为0
                car.setOnline(Integer.valueOf(GlobalConstants.SUCCESS));
            }else{
                //离线修改为1
                car.setOnline(Integer.valueOf(GlobalConstants.FAIL));
            }
        }
        carService.updateBatchById(cars);
    }

    /**
     * 考勤记录创建
     */
    @Transactional(rollbackFor = Exception.class)
    public void createAttendanceTask() {
        if (taskUtils.isTaskExist("createAttendanceTask")) {
            logger.info("createAttendanceTask任务正在执行中...");
            return;
        }
        taskUtils.addTask("createAttendanceTask",20L, TimeUnit.HOURS);
        System.out.println("开始创建考勤记录");
        //查询出所有部门
        List<SysDept> list = sysDeptService.list();

        //根据部门id查询出部门上班时间
        for (SysDept sysDept : list) {
            WorkingSchedule one = workingScheduleService.getOne(Wrappers.lambdaQuery(WorkingSchedule.class).eq(WorkingSchedule::getDeptId, sysDept.getDeptId()).last("limit 1"));

            //获取今天是周几
            int weekDay = LocalDate.now().getDayOfWeek().getValue();

            //该部门没有设置上班时间,并且它的上级都没有设置,直接跳过
            if (one == null) {
                one = workingScheduleService.getWorkingSchedule(sysDept.getParentId());
                //所有上级部门也没有设置排班,直接跳过
                if (one == null) {
                    continue;
                }
            }
            //部门排班时间
            List<Integer> array = one.getArray();

            //排班中如果包含了当前工作日,则加入考勤记录表
            if (array.contains(weekDay)) {
                //获取该部门下所有员工
                List<Employee> employees = employeeService.list(Wrappers.lambdaQuery(Employee.class).eq(Employee::getDeptId, sysDept.getDeptId()));
                List<AttendanceRecord> attendanceRecords = new LinkedList<>();
                for (Employee employee : employees) {
                    //获取该员工最近考勤记录,如果系统途中奔溃/宕机的情况,可能会出现中断一天的考勤数据,所有需要判判断最近一次的考勤记录
                    AttendanceRecord lastRecord = attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                            .eq(AttendanceRecord::getUserId, employee.getId())
                            .orderByDesc(AttendanceRecord::getAttendanceDate)
                            .last("limit 1")
                            , false);
                    //数据库中,没有这个用户的数据,只需要今天的数据
                    if (lastRecord == null) {
                        //如果当天是当天之前的日期
                        AttendanceRecord attendanceRecord = AttendanceRecord.builder()
                                .userId(employee.getId())
                                .userName(employee.getName())
                                .isRepair("0")
                                .deptId(employee.getDeptId())
                                .attendanceDate(new Date())
                                .build();
                        attendanceRecord.setCreateBy(GlobalConstants.JOB);
                        attendanceRecords.add(attendanceRecord);
                        continue;
                    }
                    Date attendanceDate = lastRecord.getAttendanceDate();
                    List<LocalDate> allDaysForBothTimes = DateUtils.getAllDaysForBothTimes(DateUtils.toLocalDate(attendanceDate), LocalDate.now());
                    s:
                    for (LocalDate localDate : allDaysForBothTimes) {

                        //如果当前不是该部门的上班时间,则跳过
                        if (!one.getArray().contains(localDate.getDayOfWeek().getValue())) {
                            //设置为休息
                            AttendanceRecord attendanceRecord = AttendanceRecord.builder()
                                    .userId(employee.getId())
                                    .userName(employee.getName())
                                    .attendance(GlobalConstants.ATTENDANCE_REST)
                                    .isRepair("0")
                                    .deptId(employee.getDeptId())
                                    .attendanceDate(DateUtils.toDate(localDate))
                                    .build();
                            attendanceRecord.setCreateBy(GlobalConstants.JOB);
                            attendanceRecords.add(attendanceRecord);
                            continue s;
                        }
                        //如果当天日期在数据库已经存在
                        if (attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                                .eq(AttendanceRecord::getUserId, employee.getId())
                                .eq(AttendanceRecord::getAttendanceDate, DateUtils.toDate(localDate)).last("limit 1")) != null) {
                            continue s;
                        }

                        //如果当天是当天之前的日期
                        AttendanceRecord attendanceRecord = AttendanceRecord.builder()
                                .userId(employee.getId())
                                .userName(employee.getName())
                                .isRepair("0")
                                .deptId(employee.getDeptId())
                                .attendanceDate(DateUtils.toDate(localDate))
                                .build();
                        attendanceRecord.setCreateBy(GlobalConstants.JOB);
                        attendanceRecords.add(attendanceRecord);
                    }
                }
                attendanceRecordService.saveBatch(attendanceRecords);
            }
        }
        System.out.println("考勤记录更新完成");
        logger.info("考勤记录更新完成");
    }

    /**
     * 考勤记录更新
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateAttendanceTask() throws ParseException {
        System.out.println("开始更新考勤记录");
        //获取当天十一点之前的打卡
        List<AttendanceRecord> attendanceRecords = attendanceRecordService.list(Wrappers.lambdaQuery(AttendanceRecord.class)
                .apply("attendance_date = '" + DateUtils.getDate() + "'")
        );
        for (AttendanceRecord attendanceRecord : attendanceRecords) {
            attendanceRecord.setCreateBy(GlobalConstants.JOB);
            //获取上班时间
            WorkingSchedule one = workingScheduleService.getOne(Wrappers.lambdaQuery(WorkingSchedule.class).eq(WorkingSchedule::getDeptId, attendanceRecord.getDeptId()).last("limit 1"));

            //查询是否为休息,如果为休息,或者请假,则不管
            if (attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                    .eq(AttendanceRecord::getUserId, attendanceRecord.getUserId())
                    .eq(AttendanceRecord::getAttendanceDate, attendanceRecord.getAttendanceDate())
                    .eq(AttendanceRecord::getAttendance, GlobalConstants.ATTENDANCE_REST).or(o -> o.eq(AttendanceRecord::getAttendance, GlobalConstants.ATTENDANCE_LEAVE)).last("limit 1")
            ) != null) {
                continue;
            }

            //上班考勤区间
            Date upWorkStartTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, attendanceRecord.getAttendanceDate()) + " " + one.getWorkStartUpTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
            Date upWorkEndTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, attendanceRecord.getAttendanceDate()) + " " + one.getWorkStartDownTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);

            //下班考勤区间
            Date downWorkStartTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, attendanceRecord.getAttendanceDate()) + " " + one.getWorkEndUpTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
            Date downWorkEndTime = DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, attendanceRecord.getAttendanceDate()) + " " + one.getWorkEndDownTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);

            //当前考勤时间
            Date attendanceUpTime = attendanceRecord.getAttendanceUpTime();
            Date attendanceDownTime = attendanceRecord.getAttendanceDownTime();

            //当前时间
            Date now = DateUtils.getNowDate();

            //有上班卡
            if (attendanceUpTime != null) {
                //上班卡迟到
                if (attendanceUpTime.compareTo(upWorkEndTime) > 0) {
                    attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_LATE);
                }else{
                    attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_NORMAL);
                }
                //有下班卡
                if (attendanceDownTime != null) {
                    continue;
                }else{
                    //没有下班卡
                    //如果当前时间大于最后下班时间
                    if (now.compareTo(downWorkEndTime) > 0) {
                        //下班卡异常
                        attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_EXCEPTION);
                    }
                }
            } else {
                //没有上班卡
                //如果当前时间超过上班卡区间
                if (now.compareTo(upWorkEndTime) > 0) {
                    //上班卡异常
                    attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_EXCEPTION);
                    //无上班卡同时无下班卡,并且时间到了下班卡结束时间
                    //如果当前时间超过了下班卡时间
                    if (now.compareTo(downWorkEndTime) > 0) {
                        attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_ABSENTEEISM);
                    }
                }else{
                    attendanceRecord.setAttendance(GlobalConstants.ATTENDANCE_NORMAL);
                }
            }
            attendanceRecordService.updateBatchById(attendanceRecords);
        }
    }

    /**
     * 更新上下班卡
     * todo 这样性能开销比较大,可以考虑在手表定位数据上传的时候去更新
     */
    public void updateClockingInTask() throws ParseException {
        //获取所有部门,然后获取部门考勤时间
        List<SysDept> depts = sysDeptService.list();
        //获取所有部门下所有员工
        List<Employee> employees = employeeService.list(Wrappers.lambdaQuery(Employee.class)
                .in(Employee::getDeptId, depts.stream().map(SysDept::getDeptId).collect(Collectors.toList()))
        );
        for (SysDept dept : depts) {
            //获取该部门的上下班时间
            WorkingSchedule one = workingScheduleService.getOne(Wrappers.lambdaQuery(WorkingSchedule.class).eq(WorkingSchedule::getDeptId, dept.getDeptId()).last("limit 1"));
            //该部门没有设置上班区间
            if(one == null){
                continue;
            }
            for (Employee employee : employees) {
                if (dept.getDeptId().equals(employee.getDeptId())) {
                    //获取当前时间
                    Date now = new Date();
                    //上班卡区间
                    String workStartUpTime = one.getWorkStartUpTime();
                    //下班卡区间
                    String workEndUpTime = one.getWorkEndUpTime();
                    //判断员工手表是否在线,如果不在线,则不打卡,直接跳过让更新考勤任务处理
                    if (GlobalConstants.OFFLINE.equals(employee.getOnline())) {
                        continue;
                    }
                    //如果员工没有手环,则跳过
                    if (employee.getImei() == null) {
                        continue;
                    }
                    //获取员工最后更新时间
                    EmployeeTrajectory lastTrajectory = employeeTrajectoryService.getOne(Wrappers.lambdaQuery(EmployeeTrajectory.class)
                            .eq(EmployeeTrajectory::getUserId, employee.getId())
                            .orderByDesc(EmployeeTrajectory::getCreateTime)
                            .last("limit 1")
                    );
                    //获取该员工当天的考勤记录
                    AttendanceRecord attendanceRecord = attendanceRecordService.getOne(Wrappers.lambdaQuery(AttendanceRecord.class)
                            .eq(AttendanceRecord::getUserId, employee.getId())
                            .eq(AttendanceRecord::getAttendanceDate, DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, now)).last("limit 1")
                    );
                    //放假时间
                    if (attendanceRecord == null){
                        continue;
                    }
                    //获取该员工绑定的区域,如果没有绑定区域,则跳过
                    AreaEmployee areaEmployee = areaEmployeeService.getOne(Wrappers.lambdaQuery(AreaEmployee.class)
                            .eq(AreaEmployee::getEmployeeId,employee.getId()).last("limit 1"),false);
                    if(areaEmployee==null){
                        continue;
                    }
                    Area area = areaService.selectAreaById(areaEmployee.getAreaId());
                    if(area==null){
                        //脏数据处理
                        continue;
                    }
                    //判断该员工是否在绑定区域内,如果不在,直接跳过
                    List<AreaLocation> areaLocations = area.getAreaLocations();
                    AreaLocation areaLocation = lastTrajectory.getAreaLocation();
                    if (!AreaLocation.isPointInPolygon(areaLocation, areaLocations)) {
                        continue;
                    }
                    //判断当前时间是否在上班开始时间后
                    if (now.compareTo(DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, now) + " " + workStartUpTime, DateUtils.YYYY_MM_DD_HH_MM_SS)) >= 0) {
                        //上班卡
                        //如果员工已经打过上班卡,则跳过
                        if (attendanceRecord.getAttendanceUpTime()!=null) {
                            continue;
                        }
                        //员工没有打上班卡,打卡
                        attendanceRecord.setAttendanceUpTime(now);
                    }
                    //判断当前时间是否在下班开始时间之后
                    if (now.compareTo(DateUtils.parseDate(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, now) + " " + workEndUpTime, DateUtils.YYYY_MM_DD_HH_MM_SS)) >= 0) {
                        //下班卡
                        //如果员工已经打过下班卡,则跳过
                        if (attendanceRecord.getAttendanceDownTime()!=null) {
                            continue;
                        }
                        //员工没有打下班班卡,打卡
                        attendanceRecord.setAttendanceDownTime(now);
                    }
                    attendanceRecordService.updateById(attendanceRecord);
                }

            }
        }
    }

    /**
     * 定时监测流转换是否启动
     */
    public void castStreamTask(){
        //获取环卫站集合
        List<Bucket> buckets = bucketService.list(Wrappers.lambdaQuery(Bucket.class)
                .eq(Bucket::getDelFlag, GlobalConstants.DEL_FLAG_NO)
                .eq(Bucket::getStatus, GlobalConstants.SUCCESS)
                .eq(Bucket::getType, GlobalConstants.BUCKET_TYPE_BUCKET_PLATFORM)
        );
        for (Bucket bucket : buckets) {
            if (!FileUtils.hasFiles(new File(ffmpegUtils.getOutputPath(String.valueOf(bucket.getId()))+"/1"))) {
                ffmpegService.start(String.valueOf(bucket.getId()), "1");
            }if (!FileUtils.hasFiles(new File(ffmpegUtils.getOutputPath(String.valueOf(bucket.getId()))+"/2"))) {
                ffmpegService.start(String.valueOf(bucket.getId()), "2");
            }if (!FileUtils.hasFiles(new File(ffmpegUtils.getOutputPath(String.valueOf(bucket.getId()))+"/3"))) {
                ffmpegService.start(String.valueOf(bucket.getId()), "3");
            }
        }
    }
    /**
     * 定时删除视频文件
     */
    public synchronized void deleteVideoTask() {
        // 获取环卫站集合
        List<Bucket> buckets = bucketService.list(Wrappers.lambdaQuery(Bucket.class)
                .eq(Bucket::getDelFlag, GlobalConstants.DEL_FLAG_NO)
                .eq(Bucket::getStatus, GlobalConstants.SUCCESS)
                .eq(Bucket::getType, GlobalConstants.BUCKET_TYPE_BUCKET_PLATFORM)
        );

        for (Bucket bucket : buckets) {
            // 获取输出路径
            String outputPath = ffmpegUtils.getOutputPath(String.valueOf(bucket.getId()));

            // 删除各个通道目录下的视频文件，但保留目录结构
            for (int i = 1; i <= 3; i++) {
                File channelDir = new File(outputPath + "/" + i);
                if (channelDir.exists() && channelDir.isDirectory()) {
                    // 只删除目录中的文件，不删除目录本身
                    File[] files = channelDir.listFiles();
                    if (files != null) {
                        for (File file : files) {
                            if (file.isFile()) {
                                file.delete();
                            }
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        System.err.println(Arrays.toString("1,2,3".split(",")));
        System.err.println(LocalDate.now().getDayOfWeek().getValue());
    }
    //判断车辆离开作业区域,进入垃圾站区域,离开垃圾站区域,进入作业区域,为一次作业

    public void updateCarTrajectoryTask(Date startTIme, Date endTime) {
        List<CarTrajectory> carTrajectories = cartrajectoryService.list(Wrappers.lambdaQuery(CarTrajectory.class)
                .eq(CarTrajectory::getDelFlag, GlobalConstants.DEL_FLAG_NO)
                .eq(CarTrajectory::getStatus, GlobalConstants.SUCCESS)
                .ge(CarTrajectory::getCreateTime, startTIme)
                .le(CarTrajectory::getCreateTime, endTime)
        );
        //判断定位数据离开区域次数
        for (CarTrajectory carTrajectory : carTrajectories) {
            if (carTrajectory.getAreaLocation() == null) {
                continue;
            }
        }
    }

    /**
     * 垃圾站容量记录
     */
    public void updateBucketCapacityTask() {
        Map<String,Object> map = bucketCapacityRecordService.get(DateUtils.getStartTime(), DateUtils.getEndTime(),null);
        //记录列表
        List<Map<String,Object>> list = (List<Map<String, Object>>) map.get("list");
        //记录次数
        int count = (int) map.get("count");
    }
}
